package org.tio.sitexxx.service.service;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.sitexxx.service.cache.CacheConfig;
import org.tio.sitexxx.service.cache.Caches;
import org.tio.sitexxx.service.service.base.UserService;
import org.tio.sitexxx.service.utils.LockUtils;
import org.tio.sitexxx.service.vo.Const;
import org.tio.sitexxx.service.vo.LoadData;
import org.tio.sitexxx.service.zk.ImServerNodeListener;
import org.tio.utils.cache.ICache;
import org.tio.utils.json.Json;
import org.tio.utils.zk.Zk;

import com.jfinal.kit.Ret;

import cn.hutool.core.util.StrUtil;

/**
 * @author tanyaowu 
 * 2016年10月19日 下午4:13:05
 */
public class ImServerService {
	private static Logger log = LoggerFactory.getLogger(ImServerService.class);

	public static final ImServerService me = new ImServerService();

	public static final UserService userService = UserService.ME;

	/**
	 * 
	 * @author: tanyaowu
	 */
	public ImServerService() {
	}

	/**
	 * 第一步：进入群组，方法返回imserver的ip，形如:192.168.1.31或im.t-io.org<br>
	 * 客户端拿到这个imserver后，进行socket通讯<br>
	 * @param groupid
	 * @return
	 * @author: tanyaowu
	 */
	public Ret imserver(String groupid) {
		if (StrUtil.isBlank(groupid)) {
			log.error("groupid is null");
			return Ret.fail("msg", "群组号为空");
		}

		ICache cache = Caches.getCache(CacheConfig.USERID_IMSERVER);
		String key = groupid + "";
		String imServer = (String) cache.get(key);

		//如果该服务器不可用，则需要重新选择服务器
		if (!ImServerNodeListener.isAvailable(imServer)) {
			Object lock = LockUtils.getLocalLockObj(LockUtils.LockPrefix.IM_SERVICE + key);
			synchronized (lock) {
				imServer = (String) cache.get(key);
				if (!ImServerNodeListener.isAvailable(imServer)) {
					cache.remove(key);
					try {
						imServer = selectImServer();
						if (StrUtil.isNotBlank(imServer)) {
							cache.put(key, imServer);
						}
					} catch (Throwable e) {
						log.error(e.toString(), e);
					}
				}
			}
		}
		log.info("进入了群组[{}]，imServer is:{}", groupid, imServer);
		return Ret.ok().set("ip", imServer);
	}

	/**
	 * @return
	 * @throws Exception
	 * @author: tanyaowu
	 */
	public String selectImServer() throws Exception {
		List<String> list = ImServerNodeListener.getImServers();
		if (list == null || list.size() == 0) {
			return null;
		}

		log.info("可用im服务器:{}", Json.toJson(list));

		int size = list.size();
		if (size == 1) {
			return list.get(0);
		}

		String ret = null;//list.get(0);
		int least = 0;
		for (int i = 0; i < size; i++) {
			String ip = list.get(i);
			String path = Const.ZkNode.IM_SERVERS + "/" + ip;
			String data = Zk.getString(path);
			if (StrUtil.isNotBlank(data)) {
				LoadData loadData = Json.toBean(data, LoadData.class);
				int tcpCount = loadData.getAppCount() + loadData.getPcCount();// + loadData.getIosCount();

				if (ret == null) { //第一次，初始化一下
					least = tcpCount;
					ret = ip;
				} else if (tcpCount <= 1000) {//长连接数小于指定值，则直接用这个服务器
					ret = ip;
					break;
				} else if (tcpCount < least) {
					least = tcpCount;
					ret = ip;
				}
			} else {
				log.warn("{}的性能数据是空", ip);
			}
		}

		if (ret == null) {
			ret = list.get(0);
		}

		return ret;
	}

}
